
/********************************************************************

    My simple calculator.

    In this file are methods of Class 'Calculator'.

********************************************************************/

//-------------------------------------------

#include "std_lib_facilities.h"

//-------------------------------------------

#include "header.h"

//-------------------------------------------

using namespace std;

//-------------------------------------------

// The greeting at the start
void Calculator::welcome()
{
    cout << "Welcome to the calculator program!\n";
    cout << "Please 'info' or 'help' for getting help.";
    cout << "\nEnter an expression:\n\n";
}

//-------------------------------------------

// Deleting data from a class
void Calculator::cleardate()
{
    str      = " ";
    str_part = " ";
    t.kind   = ' ';
    t.name   = " ";
    t.value  = 0;
    tok.clear();
}

//-------------------------------------------

// Read user data
void Calculator::get()
{
    vars.var_table_intial_value();
    cin >> str;
    strexpression(str,t,tok);
    if( nocalculation == false ){
        validationstrexpression();
        result = calculation();
    }
    cleardate();
}

void Calculator::get( string &str )
{
    vars.var_table_intial_value();
    cin >> str;
    strexpression(str,t,tok);
    if( nocalculation == false ){
        validationstrexpression();
        result = calculation();
    }
    cleardate();
}

//-------------------------------------------

// The output
void Calculator::out()
{
    if( nocalculation == false ) cout << "= " << result << "\n";
    else nocalculation = false;
}

//-------------------------------------------



/********************************************

    Convert user string into tokens.

********************************************/

//-------------------------------------------

// Parsing custom string
void Calculator::strexpression( string &str, Calculatortoken &t, vector<Calculatortoken> &tok  )
{
    int  brace_open  = 0;
    int  brace_close = 0;
    vector<int> brace_minusone;
    bool figurebrace_minusone = false;
    int  figurebrace_open     = 0;
    int  figurebrace_close    = 0;

    for( int i = 0 ; i < str.size() ; ++i ){
        switch( str[i] ){
            case '+':
                char_plus(i); break;
            case '-':
                char_minus(i,brace_open,brace_minusone,figurebrace_minusone); break;
            case '*':
                char_multiply(i); break;
            case '/':
                char_divide(i); break;
            case '%':
                char_percent(i); break;
            case '!':
                char_exclamation(i); break;
            case '(':
                char_roundbrace_open(i,brace_open); break;
            case ')':
                char_roundbrace_close(i,brace_open,brace_close,brace_minusone); break;
            case '{':
                char_figurebrace_open(i,figurebrace_open); break;
            case '}':
                char_figurebrace_close(i,figurebrace_open,figurebrace_close,brace_close,figurebrace_minusone,brace_minusone); break;
            case '.':
                char_point(); break;
            case ',':
                char_separator(i); break;
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
                if( i > 0 && (( int(str[i-1]) >= 65 && int(str[i-1]) <= 90 ) || ( int(str[i-1]) >= 97 && int(str[i-1]) <= 122 )) ){ char_letter(i); break; }
                else{ char_number(i); break; }
            case 'a': case 'b': case 'c': case 'd': case 'e':
            case 'f': case 'g': case 'h': case 'i': case 'j':
            case 'k': case 'l': case 'm': case 'n': case 'o':
            case 'p': case 'q': case 'r': case 's': case 't':
            case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
            case 'A': case 'B': case 'C': case 'D': case 'E':
            case 'F': case 'G': case 'H': case 'I': case 'J':
            case 'K': case 'L': case 'M': case 'N': case 'O':
            case 'P': case 'Q': case 'R': case 'S': case 'T':
            case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_':
                char_letter(i); break;
            case '=':
                char_equal(i); break;
            default:
                throw errordefault(); break;
        }
        if( str_part == "info" || str_part == "help" ){
            nocalculation = true;
            vars.variable_info();
            cleardate();
        }else if( i == str.size()-1 &&
            tok[tok.size()-1].kind != number &&
            tok[tok.size()-1].kind != ')' &&
            tok[tok.size()-1].kind != '}' &&
            tok[tok.size()-1].kind != '!' ){
            if( variable_or_number() == true )
                putintoken(t,tok,variable);
            else
                putintoken(t,tok,number);
        }
    }
    //strnum_cout();
}

//-------------------------------------------

// Determination of the number (false) of variable (true) in the string
bool Calculator::variable_or_number()
{
    for( int i = 0 ; i < str_part.size() ; ++i ){
        if( ( int(str_part[i]) >= 65 && int(str_part[i]) <= 90 ) || ( int(str_part[i]) >= 97 && int(str_part[i]) <= 122 ) ) return true;
    }
    return false;
}

//-------------------------------------------

// The addition symbol in the string
void Calculator::char_plus( int i )
{
    if( str_part != " " ){
        if( i+1 < str.size() && str[i+1] != ')' && str[i+1] != '}' ){
            if( variable_or_number() == true )
                putintoken(t,tok,variable);
            else
                putintoken(t,tok,number);
            putintoken(t,tok,'+');
        }
    }else if( str_part == " " ){
        if( i != 0 ){
            if( int(str[i-1]) >= 0 && int(str[i-1]) != ')' && int(str[i-1]) != '}' && int(str[i-1]) != '!' ){
                str_part = "+";
            }else{
                if( i+1 < str.size() && str[i+1] != ')' && str[i+1] != '}' && str[i+1] != '!' )
                    putintoken(t,tok,'+');
            }
        }
    }
}

//-------------------------------------------

// The difference symbol in the string
void Calculator::char_minus( int i, int &brace_open, vector<int> &brace_minusone, bool &figurebrace_minusone )
{
    if( str_part != " " ){
        if( i+1 < str.size() && ( str[i+1] != ')' || str[i+1] != '}' || str[i+1] != '!' ) ){
            if( variable_or_number() == true )
                putintoken(t,tok,variable);
            else
                putintoken(t,tok,number);
            putintoken(t,tok,'-');
        }
    }else if( str_part == " " ){
        if( ( i == 0 && ( str[i+1] == '(' || str[i+1] == '{' || str[i+1] == '!' ) ) ||
                ( i > 0 && i+1 < str.size() &&
                ( str[i-1] != ')' && str[i-1] != '}' && str[i-1] != '!' ) &&
                ( str[i+1] == '(' || str[i+1] == '{' || str[i+1] == '!' )) ){
            putintoken(t,tok,'(', ++brace_open);
            brace_minusone.push_back(brace_open);
            if( str[i+1] == '{' ) figurebrace_minusone = true;
            if( variable_or_number() == true )
                putintoken(t,tok,variable,-1);
            else
                putintoken(t,tok,number,-1);
            putintoken(t,tok,'*');
        }else if( ( i == 0 && i+1 < str.size() && str[i+1] != '(' && str[i+1] != '{' && str[i+1] != '!' ) || ( i-1 >= 0 && str[i-1] != ')' && str[i-1] != '}' && str[i-1] != '!' ) ){
            str_part = "-";
        }else {
            if( i+1 < str.size() && str[i+1] != ')' && str[i+1] != '}' && str[i+1] != '!' )
                putintoken(t,tok,'-');
        }
    }
}

//-------------------------------------------

// The multiplication symbol in the string
void Calculator::char_multiply( int i )
{
    if( i+1 < str.size() && str[i+1] != ')' && str[i+1] != '}' && str[i+1] != '!' ){
        if( str_part != " " )
            if( variable_or_number() == true )
                putintoken(t,tok,variable);
            else
                putintoken(t,tok,number);
        if( i-1 >= 0 && str[i-1] != '(' && str[i-1] != '{' )
            putintoken(t,tok,'*',0);
    }
}

//-------------------------------------------

// The division symbol in the string
void Calculator::char_divide( int i )
{
    if( i+1 < str.size() && str[i+1] != ')' && str[i+1] != '}' && str[i+1] != '!' ){
        if( str_part != " " )
            if( variable_or_number() == true )
                putintoken(t,tok,variable);
            else
                putintoken(t,tok,number);
        if( i-1 >= 0 && str[i-1] != '(' && str[i-1] != '{' )
            putintoken(t,tok,'/');
    }
}

//-------------------------------------------

// The percent symbol in the string
void Calculator::char_percent( int i )
{
    if( i+1 < str.size() && str[i+1] != ')' && str[i+1] != '}' && str[i+1] != '!' ){
        if( str_part != " " )
            if( variable_or_number() == true )
                putintoken(t,tok,variable);
            else
                putintoken(t,tok,number);
        if( i-1 >= 0 && str[i-1] != '(' && str[i-1] != '{' )
            putintoken(t,tok,'%');
    }
}

//-------------------------------------------

// The exclamation symbol in the string
void Calculator::char_exclamation( int i )
{
    if( i != 0 && i-1 >= 0 && ( str[i-1] == ')' || str[i-1] == '}' || str[i-1] == '!' ) ){
        putintoken(t,tok,'!');
    }else if( i != 0 && i-1 >= 0 && ((int(str[i-1]) >= 48 && int(str[i-1]) <= 57) || (int(str[i-1]) >= 65 && int(str[i-1]) <= 90) || (int(str[i-1]) >= 97 && int(str[i-1]) <= 122)) ){
        if( variable_or_number() == true )
            putintoken(t,tok,variable);
        else
            putintoken(t,tok,number);
        putintoken(t,tok,'!');
    }else throw errorfactorial();
}

//-------------------------------------------

// The opening parenthesis symbol in the string
void Calculator::char_roundbrace_open( int i, int &brace_open )
{
    if( str_part != " " ){
        if( variable_or_number() == true ){
            putintoken(t,tok,variable);
            if( tok[tok.size()-1].name != "sqrt" && tok[tok.size()-1].name != "pow" )
                putintoken(t,tok,'*');
        }else{
            putintoken(t,tok,number);
            putintoken(t,tok,'*');
        }
    }else if( i-1 >= 0 && ( str[i-1] == ')' || str[i-1] == '}' || str[i-1] == '!' ) )
        putintoken(t,tok,'*');
    putintoken(t,tok,'(', ++brace_open);
}

//-------------------------------------------

// The closing parenthesis symbol in the string
void Calculator::char_roundbrace_close( int i, int &brace_open, int &brace_close, vector<int> &brace_minusone )
{
    if( str_part != " " ){
        if( variable_or_number() == true )
            putintoken(t,tok,variable);
        else
            putintoken(t,tok,number);
    }
    putintoken(t,tok, ')', brace_search(brace_open,')') );
    ++brace_close;
    if( brace_minusone.size() > 0 && brace_minusone[brace_minusone.size()-1] == t.value-1 ){
        putintoken(t,tok,')', brace_minusone[brace_minusone.size()-1]);
        ++brace_close;
        brace_minusone.pop_back();
    }
    if( i+1 < str.size() && (( int(str[i+1]) >= 48 && int(str[i+1]) <= 57 ) || ( int(str[i+1]) >= 65 && int(str[i+1]) <= 90 ) || ( int(str[i+1]) >= 97 && int(str[i+1]) <= 122 )) )
        putintoken(t,tok,'*');
}

//-------------------------------------------

// The opening curly braces symbol in the string
void Calculator::char_figurebrace_open( int i, int &figurebrace_open )
{
    if( str_part != " " ){
        if( variable_or_number() == true ){
            putintoken(t,tok,variable);
            if( tok[tok.size()-1].name != "sqrt" || tok[tok.size()-1].name != "pow" )
                putintoken(t,tok,'*');
        }else{
            putintoken(t,tok,number);
            putintoken(t,tok,'*');
        }
    }else if( i-1 >= 0 && ( str[i-1] == ')' || str[i-1] == '}' || str[i-1] == '!' ) )
        putintoken(t,tok,'*');
    putintoken(t,tok,'{', ++figurebrace_open);
}

//-------------------------------------------

// The closing curly braces symbol in the string
void Calculator::char_figurebrace_close( int i, int &figurebrace_open, int &figurebrace_close, int &brace_close, bool &figurebrace_minusone, vector<int> &brace_minusone )
{
    if( str_part != " " ){
        if( variable_or_number() == true )
            putintoken(t,tok,variable);
        else
            putintoken(t,tok,number);
    }
    putintoken(t,tok,'}', brace_search(figurebrace_open, '{'));
    ++figurebrace_close;
    if( figurebrace_minusone == true && brace_minusone.size() > 0 ){
        putintoken(t,tok,')', brace_minusone[brace_minusone.size()-1]);
        ++brace_close;
        brace_minusone.pop_back();
        figurebrace_minusone = false;
    }
    if( i+1 < str.size() && (( int(str[i+1]) >= 48 && int(str[i+1]) <= 57 ) || ( int(str[i+1]) >= 65 && int(str[i+1]) <= 90 ) || ( int(str[i+1]) >= 97 && int(str[i+1]) <= 122 )) )
        putintoken(t,tok,'*');
}

//-------------------------------------------

// The definition of the type of brackets
void Calculator::brace_definition( char bracevar, vector<char> &braces )
{
    char br_open  = '(';
    char br_close = ')';
    if( bracevar == '{' || bracevar == '}' ){
        br_open  = '{';
        br_close = '}';
    }else
    if( bracevar == '[' || bracevar == ']' ){
        br_open  = '[';
        br_close = ']';
    }else
    if( bracevar == '<' || bracevar == '>' ){
        br_open  = '<';
        br_close = '>';
    }
    braces.push_back(br_open);
    braces.push_back(br_close);
}

//-------------------------------------------

// Search the opening and closing brackets in the vector "tok"
int Calculator::brace_search( int brace_open, char bracevar )
{
    vector<char> bracesvar;
    brace_definition( bracevar, bracesvar );
    char br_open  = bracesvar[0];
    char br_close = bracesvar[1];
    for( int k = tok.size()-1 ; k >= 0 ; --k ){
        if( tok[k].kind == br_open ){
            break;
        }else if( tok[k].kind == br_close ){
            for( int m = k ; m >= 0 ; --m ){
                if( tok[m].kind == br_close && tok[m].value == tok[k].value ){
                    --brace_open;
                }
            }
        }
    }
    return brace_open;
}

//-------------------------------------------

// Separator for use in functions
void Calculator::char_separator( int i )
{
    if( i-1 > 0 && i+1 < str.size() && str[i+1] != ')' && str[i+1] != '}' && str[i+1] != '!' ){
        if( str_part != " " )
            if( variable_or_number() == true )
                putintoken(t,tok,variable);
            else
                putintoken(t,tok,number);
        if( str[i-1] != '(' && str[i-1] != '{' )
            putintoken(t,tok,',',0);
    }
}

//-------------------------------------------

// The dot character in the string
void Calculator::char_point()
{
    if( str_part == " " ) str_part = ".";
    else str_part += '.';
}

//-------------------------------------------

// Number in the string
void Calculator::char_number( int i )
{
    if( str_part == " " ) str_part = str[i];
    else str_part += str[i];
}

//-------------------------------------------

// The transformation of the string
// that contains digits and the dot
// in a floating point number
double Calculator::strnum()
{
    double n   = 0;
    int offset = 0;
    bool point = false;
    for( int i = 0 ; i < str_part.size() ; ++i ){
        switch( str_part[i] ){
            case '.':
                offset = i;
                point  = true; break;
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
                n      = strnum_offset( n, (str_part[i] - '0'), i, point, offset ); break;
            default:
                break;
        }
    }
    if( str_part[0] == '-' ) n *= -1;
    return n;
}

//-------------------------------------------

// The displacement of the position of digits
// in a floating point number
double Calculator::strnum_offset( double n, int num, int i, bool point, int offset )
{
    if( i == 0 ){
        n = num;
    }else{
        if( point == false ){
            n *= 10;
            n += num;
        }else if( point == true ){
            double k = 1;
            for( int m = 0; m < (i-offset); ++m ){
                k *= 10;
            }
            n += num / k;
        }
    }
    return n;
}

//-------------------------------------------

// The letter symbol in the string
void Calculator::char_letter( int i )
{
    if( str_part == " " ) str_part = str[i];
    else if( int(str_part[str_part.size()-1]) >= 48 && int(str_part[str_part.size()-1]) <= 57 ){
        putintoken(t,tok,number);
        putintoken(t,tok,'*');
        str_part = " ";
        str_part = str[i];
    }
    else str_part += str[i];
}

//-------------------------------------------

// The equal symbol in the string
void Calculator::char_equal( int i )
{
    if( str[i] = '=' ){
        for( int j = i+1 ; j < str.size() ; ++j ){
            if( str[j] == '=' ) throw errorequalscorrect();
        }
        if( str_part != " " ){
            if( variable_or_number() == true ) putintoken(t,tok,variable);
            else putintoken(t,tok,number);
        }
        putintoken(t,tok,'=');
    }
}

//-------------------------------------------

// Adding tokens without values in the vector "tok"
void Calculator::putintoken( Calculatortoken &t, vector<Calculatortoken> &tok, char ch )
{
    if(       ch == variable ){
        t.kind   =  variable;
        t.name   =  str_part;
        t.value  =  vars.set_variable_value( str_part );
        tok.push_back(t);
        t.name   = " ";
        str_part = " ";
    }else if( ch == number ){
        t.kind   =  number;
        t.value  =  strnum();
        tok.push_back(t);
        str_part = " ";
    }else if( ch == '.' ){
        t.kind   =  number;
        t.value  =  strnum();
        tok.push_back(t);
        str_part = " ";
    }else if( ch == '*' || ch == '/' || ch == '%' || ch == '!' ||
              ch == '+' || ch == '-' ||
              ch == '(' || ch == ')' ||
              ch == '{' || ch == '}' ||
              ch == '=' || ch == ',' ){
        t.kind   =  ch;
        t.value  =  0;
        tok.push_back(t);
        str_part = " ";
    }
}

//-------------------------------------------

// Adding tokens to the value in the vector "tok"
void Calculator::putintoken( Calculatortoken &t, vector<Calculatortoken> &tok, char ch, double n )
{
    if(       ch == variable ){
        t.kind   =  variable;
        t.name   =  str_part;
        t.value  =  vars.set_variable_value( str_part, n );
        tok.push_back(t);
        t.name   = " ";
        str_part = " ";
    }else if( ch == number ){
        t.kind   = number;
        t.value  = n;
        tok.push_back(t);
        str_part = " ";
    }else if( ch == '.' ){
        t.kind   = number;
        t.value  = n;
        tok.push_back(t);
        str_part = " ";
    }else if( ch == '*' || ch == '/' || ch == '%' || ch == '!' ||
              ch == '+' || ch == '-' ||
              ch == '(' || ch == ')' ||
              ch == '{' || ch == '}' ||
              ch == ',' ){
        t.kind   = ch;
        t.value  = n;
        tok.push_back(t);
        str_part = " ";
    }
}

//-------------------------------------------



/********************************************

    Erase tokens.

********************************************/

//-------------------------------------------

// Removing consecutive duplicated elements from a vector 'tok'
Calculator::tokenerase()
{
    if( tok.size() > 1 ){
        for( int i = 0 ; i < tok.size() ; ++i ){
            if( tok[i].kind == number ){
                if( i+1 < tok.size() && tok[i+1].kind == number && tok[i].value == tok[i+1].value ){
                    tok.erase(tok.begin()+i+1);
                }
                if( i-1 > 0 && tok[i-1].kind == number && tok[i].value == tok[i-1].value ){
                    tok.erase(tok.begin()+i-1);
                }
            }
        }
    }
}

//-------------------------------------------

// Remove values from a vector 'tok' after the operation of addition
Calculator::tokeneraseafteroperation( int &n, int ago, int forvard, int &tokbegin, int &tokbefor )
{
    if( tok.size() > 1 && n-ago >= 0 && n+forvard < tok.size() ){
        if( forvard > 0 ){
            for( int i = n+1 ; i <= n+forvard ; ++i ){
                tok.erase(tok.begin()+n+1);
                --tokbefor;
            }
        }
        if( ago > 0 ){
            int nin = n;
            for( int i = n-1 ; i >= nin-ago ; --i ){
                tok.erase(tok.begin()+n-1);
                --tokbegin;
                --n;
            }
        }
    }
}

//-------------------------------------------



/********************************************

    Calculations.

********************************************/

//-------------------------------------------

// The feature that unites all the calculations
double Calculator::calculation()
{
    double dbl       = 0;
    bool figurebrace = false;
    bool brace       = false;
    bool operators   = true;
    int start  = 0;
    int finish = tok.size();
    do{
        dbl = calcoperation( dbl, operators );
        figurebrace = braceconverce( '{' );
        brace       = braceconverce( '(' );
        figurebrace = braceconverce( '{' );
        brace       = braceconverce( '(' );
        dbl = calcoperation( dbl, operators );
    }while( figurebrace == false || brace == false || operators == true );
    dbl = equals( dbl );
    return dbl;
}

//-------------------------------------------

// The calculation without brackets
double Calculator::calcoperation( double dbl, bool &operators )
{
    dbl = variable_sqrt( dbl );
    dbl = variable_pow( dbl );
    dbl = calcoperationinbrace( dbl, '*', '(' );
    dbl = calcoperationinbrace( dbl, '*', '({' );
    dbl = calcoperationinbrace( dbl, '+', '(' );
    dbl = calcoperationinbrace( dbl, '+', '({' );
    dbl = factorial( dbl );
    dbl = multiplication_and_division( dbl );
    dbl = addition_and_subtraction( dbl );
    tokenerase();
    operators = false;
    for( int i = 0 ; i < tok.size() ; ++i ){
        if( tok[i].kind == '*' || tok[i].kind == '/' || tok[i].kind == '+' || tok[i].kind == '-' || tok[i].kind == '!' || tok[i].name == "sqrt" ){
            operators = true;
        }
    }
    return dbl;
}

//-------------------------------------------

// The calculation without brackets
double Calculator::calcoperationinbrace( double dbl, char sign, char bracevar )
{
    vector<char> bracesvar;
    brace_definition( bracevar, bracesvar );
    char br_open  = bracesvar[0];
    char br_close = bracesvar[1];
    for( int i = 0 ; i < tok.size() ; ++i ){
        if( tok[i].kind == br_open ){
            for( int j = i+1 ; j < tok.size() ; ++j ){
                if( tok[j].kind == '(' || tok[j].kind == '{' ) break;
                if( tok[j].kind == br_close ){
                    if( sign == '*' ) dbl = multiplication_and_division( dbl, i, j );
                    else
                    if( sign == '+' ) dbl = addition_and_subtraction( dbl, i, j );
                    braceconverce( '{' );
                    braceconverce( '(' );
                }
            }
        }
    }
    return dbl;
}

//-------------------------------------------

bool Calculator::num_or_var( int n )
{
    if( tok[n].kind == number || tok[n].kind == variable ) return true;
    else return false;
}

bool Calculator::num_or_var( int n1, int n2 )
{
    bool nv = false;
    if( tok[n1].kind == number || tok[n1].kind == variable ) nv = true;
    else nv = false;
    if( tok[n2].kind == number || tok[n2].kind == variable ) nv = true;
    else nv = false;
    return nv;
}

bool Calculator::num_or_var( int n1, int n2, int n3 )
{
    bool nv = false;
    if( tok[n1].kind == number || tok[n1].kind == variable ) nv = true;
    else nv = false;
    if( tok[n2].kind == number || tok[n2].kind == variable ) nv = true;
    else nv = false;
    if( tok[n3].kind == number || tok[n3].kind == variable ) nv = true;
    else nv = false;
    return nv;
}

//-------------------------------------------

//bool Calculator::braceconverce( char bracevar, int &tokbegin, int &tokbefore )
bool Calculator::braceconverce( char bracevar )
{
    vector<char> bracesvar;
    brace_definition( bracevar, bracesvar );
    char br_open  = bracesvar[0];
    char br_close = bracesvar[1];
    for( int i = 0; i < tok.size(); ++i ){
        if( tok[i].kind == br_open && i+1 < tok.size() && num_or_var(i+1) ){
            for( int j = i; j < tok.size(); ++j ){
                if( tok[j].kind == '*' || tok[j].kind == '/' || tok[j].kind == '+' || tok[j].kind == '-' || tok[j].kind == '%' || tok[j].kind == ',' ){
                    break;
                }else if( tok[j].kind == br_close ){
                    tok.erase(tok.begin()+j);
                    tok.erase(tok.begin()+i);
                    break;
                }
            }
        }
    }
    for( int i = 0; i < tok.size(); ++i ){
        if( tok[i].kind == '(' || tok[i].kind == ')' || tok[i].kind == '{' || tok[i].kind == '}' )
            return false;
    }
    return true;
}

//-------------------------------------------

// Calculation the square root
double Calculator::variable_sqrt( double dbl )
{
    int k = 0;
    for( int i = 0 ; i < tok.size(); ++i ){
        if( tok[i].name == "sqrt" && num_or_var(i+1) ){
            dbl = sqrt(tok[i+1].value);
            tok[i].kind  = number;
            tok[i].value = dbl;
            tok[i].name  = " ";
            tokeneraseafteroperation(i,0,1,k,k);
        }
    }
    return dbl;
}

//-------------------------------------------

// Calculation pow()
double Calculator::variable_pow( double dbl )
{
    int k = 0;
    for( int i = 0 ; i < tok.size(); ++i ){
        if(tok[i].name   == "pow" &&
           tok[i+1].kind == '(' &&
           num_or_var(i+2) &&
           tok[i+3].kind == ',' &&
           num_or_var(i+4) &&
           tok[i+5].kind == ')' ){
            dbl = pow(tok[i+2].value,tok[i+4].value);
            tok[i].kind  = number;
            tok[i].value = dbl;
            tok[i].name  = " ";
            tokeneraseafteroperation(i,0,5,k,k);
        }
    }
    return dbl;
}

//-------------------------------------------

// Multiplication and division
double Calculator::multiplication_and_division( double dbl )
{
    int k = 0;
    for( int i = 0; i < tok.size(); ++i ){
        if ( tok[i].kind == '*' && num_or_var(i-1,i+1) ) {
            dbl = tok[i-1].value * tok[i+1].value;
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,k);
        }else
        if ( tok[i].kind == '/' && num_or_var(i-1,i+1) ) {
            if( tok[i+1].value == 0 ) throw divisionbyzero();
            dbl = tok[i-1].value / tok[i+1].value;
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,k);
        }else
        if ( tok[i].kind == '%' && num_or_var(i-1,i+1) ) {
            dbl = tok[i-1].value - tok[i+1].value * int(tok[i-1].value / tok[i+1].value);// if double number
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,k);
        }
    }
    return dbl;
}

//-------------------------------------------

// Multiplication and division in a certain range of tokens vector
double Calculator::multiplication_and_division( double dbl, int &k, int &m )
{
    for( int i = k; i < m; ++i ){
        if( tok[i].kind == ')' || tok[i].kind == '}' ){
            break;
        }else
        if( tok[i].kind == '*' && num_or_var(i-1,i+1) ){
            dbl = tok[i-1].value * tok[i+1].value;
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,m);
        }else
        if( tok[i].kind == '/' && num_or_var(i-1,i+1) ){
            if( tok[i+1].value == 0 ) throw divisionbyzero();
            dbl = tok[i-1].value / tok[i+1].value;
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,m);
        }else
        if( tok[i].kind == '%' && num_or_var(i-1,i+1) ) {
            dbl = tok[i-1].value - tok[i+1].value * int(tok[i-1].value / tok[i+1].value);
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,m);
        }
    }
    return dbl;
}

//-------------------------------------------

// Addition and subtraction
double Calculator::addition_and_subtraction( double dbl )
{
    int k = 0;
    for( int i = 0; i < tok.size(); ++i ){
        if ( tok[i].kind == '+' && num_or_var(i-1,i+1) ) {
            dbl = tok[i-1].value + tok[i+1].value;
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,k);
        }else if( tok[i].kind == '-' && num_or_var(i-1,i+1) ) {
            dbl = tok[i-1].value - tok[i+1].value;
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,k);
        }
    }
    return dbl;
}

//-------------------------------------------

// Addition and subtraction in a certain range of tokens vector
double Calculator::addition_and_subtraction( double dbl, int &k, int &m )
{
    for( int i = k; i < m; ++i ){
        if( tok[i].kind == ')' || tok[i].kind == '}' ){
            break;
        }else if( tok[i].kind == '+' && num_or_var(i-1,i+1) ) {
            dbl = tok[i-1].value + tok[i+1].value;
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,m);
        }else if( tok[i].kind == '-' && num_or_var(i-1,i+1) ) {
            dbl = tok[i-1].value - tok[i+1].value;
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,1,k,m);
        }
    }
    return dbl;
}

//-------------------------------------------

// Factorial
double Calculator::factorial( double dbl )
{
    int k = 0;
    bool mins = false;
    for( int i = 0 ; i < tok.size() ; ++i ){
        if( tok[i].kind == '!' && i-1 >= 0 && num_or_var(i-1) ){
            dbl = int(tok[i-1].value);
            if( dbl == 0 ) dbl = 1;
            else{
                if ( dbl-1 < 0 ){
                    dbl *= -1;
                    mins = true;
                }
                for( int j = dbl-1; j >= 1; --j ){
                    dbl *= j;
                }
                if( mins == true ){
                    dbl *= -1;
                    mins = false;
                }
            }
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,0,k,k);
        }
    }
    return dbl;
}

//-------------------------------------------

// Factorial in a certain range of tokens vector
double Calculator::factorial( double dbl, int &k, int &m )
{
    bool mins = false;
    for( int i = k ; i < m ; ++i ){
        if( tok[i].kind == '!' && i-1 >= 0 && num_or_var(i-1) ){
            dbl = int(tok[i-1].value);
            if( dbl == 0 ) dbl = 1;
            else{
                if ( dbl-1 < 0 ){
                    dbl *= -1;
                    mins = true;
                }
                for( int j = dbl-1; j >= 1; --j ){
                    dbl *= j;
                }
                if( mins == true ){
                    dbl *= -1;
                    mins = false;
                }
            }
            tok[i].kind  = number;
            tok[i].value = dbl;
            tokeneraseafteroperation(i,1,0,k,m);
        }
    }
    return dbl;
}

//-------------------------------------------

// Assignment operations
double Calculator::equals( double dbl )
{
    int k = 0; int m = 0;
    for( int i = 0 ; i < tok.size() ; ++i ){
        if( tok[i].kind == '=' ){
            if( i > 0 && i < tok.size()-1 ){
                if( tok[i-1].kind == variable && tok[i-1].name != " " && num_or_var(i+1) ){
                    string snam    = tok[i-1].name;
                    tok[i].kind    = '8';
                    tok[i].name    = " ";
                    tok[i].value   = tok[i+1].value;
                    dbl            = tok[i].value;
                    vars.var_table_push_back( tok[i-1].name, tok[i].value );
                    tokeneraseafteroperation(i,1,1,k,m);
                }else if( tok[i-1].value == tok[i+1].value ){
                    tok[i].kind    = '8';
                    tok[i].name    = " ";
                    tok[i].value   = tok[i+1].value;
                    dbl            = tok[i+1].value;
                    tokeneraseafteroperation(i,1,1,k,m);
                }
                else {
                    throw errorequalscorrect();
                }
            }
        }
    }
    return dbl;
}

//-------------------------------------------



/********************************************

    Validation

********************************************/

//-------------------------------------------

// Determination of the correctness of operations
void Calculator::validationstrexpression()
{
    bool operands        = false;
    bool operators       = false;
    bool twooperators    = false;
    bool emptybraces     = false;
    bool bracescorrect   = false;
    bool separatecorrect = true;
    bool sqrtcorrect     = true;
    bool powcorrect      = true;
    int  start           = 0;
    int  finish          = tok.size();
    for( int i = 0; i < tok.size(); ++i ){
        if( tok[i].kind == '8' ){
            operands = true;
        }else if( tok[i].name != " " ){
            operands = true;
        }else if( tok[i].kind == '!' ){
            operators = true;
        }else if( tok[i].kind == '*' || tok[i].kind == '/' || tok[i].kind == '+' || tok[i].kind == '-' || tok[i].kind == '%' || tok[i].kind == '=' ){
            operators = true;
            if( i+1 < tok.size() ){
                if( tok[i+1].kind == '*' || tok[i+1].kind == '/' || tok[i+1].kind == '+' || tok[i+1].kind == '%' || tok[i+1].kind == '!' || tok[i+1].kind == '=' ){
                    twooperators = true;
                }
            }
        }else if( tok[i].kind == '{' ){
            if( i+1 < tok.size() ){
                if( tok[i+1].kind == '}' ) emptybraces = true;
            }
        }else if( tok[i].kind == '(' ){
            if( i+1 < tok.size() ){
                if( tok[i+1].kind == ')' ) emptybraces = true;
            }
        }else if( tok[i].kind == ',' ){
            operators = true;
            start  = 0;
            finish = tok.size();
            bracescorrect = bracecorrect( start, finish );
            if( bracescorrect == true ){
                start  = 0;
                finish = i-1;
                bool bracescorrect1 = bracecorrect( start, finish );
                start  = i+1;
                finish = tok.size();
                bool bracescorrect2 = bracecorrect( start, finish );
                if( bracescorrect1 == false && bracescorrect2 == false ){
                    for( int j = i-1 ; j >= 0 ; --j ){
                        if( tok[j].name == "pow" && tok[j+1].kind == '(' ){
                            separatecorrect = true;
                            powcorrect      = true;
                        }
                    }
                    if( separatecorrect == false ){
                        powcorrect      = false;
                    }
                }else separatecorrect   = false;
            }else separatecorrect       = false;
            break;
        }
        if( tok[i].name == "sqrt" ){
            if( i+3 < tok.size() && tok[i+1].kind == '(' ){
                operators     = true;
                operands      = true;
                sqrtcorrect   = true;
            }else sqrtcorrect = false;
        }else if( tok[i].name == "info" || tok[i].name == "help" ){
            operators = true;
            operands  = true;
        }
    }
    if( bracescorrect == false ){
        start  = 0;
        finish = tok.size();
        bracescorrect = bracecorrect( start, finish );
    }
    if( operands        == false ) throw errornooperands();
    if( operators       == false ) throw errornooperators();
    if( twooperators    == true  ) throw errortwooperatorsinarow();
    if( emptybraces     == true  ) throw erroremptybraces();
    if( separatecorrect == false ) throw errorseparatorcorrect();
    if( bracescorrect   == false ) throw errorbracecorrect();
    if( sqrtcorrect     == false ) throw errorsqrtcorrect();
    if( powcorrect      == false ) throw errorpowcorrect();
}

//-------------------------------------------

// The definition of the proper use of parentheses
bool Calculator::bracecorrect( int start, int finish )
{
    int  figurebrace_num = 0;
    int  brace_num       = 0;
    for( int i = start ; i < finish ; ++i ){
        switch( tok[i].kind ){
        case '{':
            ++figurebrace_num;
            bracecorrectclose( i, '{' );
            break;
        case '(':
            ++brace_num;
            bracecorrectclose( i, '(' );
            break;
        case '}':
            --figurebrace_num;
            break;
        case ')':
            --brace_num;
            break;
        default:
            break;
        }
    }
    if( figurebrace_num == 0 && brace_num == 0 ){
        return true;
    }else{
        return false;
    }
}

//-------------------------------------------

// Validation of closing brackets
void Calculator::bracecorrectclose( int i, char braceopenchar )
{
    char braceclosechar;
    int figurebrace_num = 0;
    int brace_num       = 0;
    if( braceopenchar  == '{' ){
        braceclosechar  = '}';
        figurebrace_num = 1;
    }else
    if( braceopenchar  == '(' ){
        braceclosechar  = ')';
        brace_num       = 1;
    }

    for( int j = i+1; j < tok.size(); ++j ){
        if( tok[j].kind == braceclosechar && tok[j].value == tok[i].value ){
            if( braceopenchar == '{' ) --figurebrace_num;
            else if( braceopenchar == '(' ) --brace_num;
            if( figurebrace_num != 0 || brace_num != 0 ){
                throw errorbracecorrect();
            }
            break;
        }else if( tok[j].kind == '(' ){
            ++brace_num;
        }else if( tok[j].kind == ')' ){
            --brace_num;
        }else if( tok[j].kind == '{' ){
            ++figurebrace_num;
        }else if( tok[j].kind == '}' ){
            --figurebrace_num;
        }
    }
}

//-------------------------------------------



/********************************************

    Debug.
    The output information
    on the screen.

********************************************/

//-------------------------------------------

// Display the contents of the vector with the tokens "tok" in an expression
void Calculator::coutkind( int i, double d )
{
    if( tok[i].kind == '!' ){
        cout << '\n' << tok[i-1].value << ' ' << tok[i].kind << " = " << d << '\n';
    }else{
        cout << '\n' << tok[i-1].value << ' ' << tok[i].kind << ' ' << tok[i+1].value << " = " << d << '\n';
    }
}

//-------------------------------------------

// Display the contents of the vector with the tokens "tok"
void Calculator::strnum_cout()
{
    cout << '\n';
    for( int i = 0 ; i < tok.size() ; ++i ){
        if( tok[i].value < 0 ) cout << ' ';
        cout << tok[i].kind << ' ';
    }
    cout << '\n';
    for( int i = 0 ; i < tok.size() ; ++i ){
        cout << tok[i].value << ' ';
    }
    cout << '\n';
    for( int i = 0 ; i < tok.size() ; ++i ){
        cout << tok[i].name << ' ';
    }
    cout << '\n';
    char che = ' ';
    cin >> che;
}

//-------------------------------------------
